#include "md2\md2Player.h"
#include "hero.h"
#include "camera.h"
#include "terrain.h"
#include "FrustumG.h"
#include "definitions.h"
#include "toolkits/includes/glut.h"
#include "toolkits/includes/il.h"

extern Hero *heroClass;
extern Md2Player *jogador;
extern Terrain *terrainClass;
extern float xpos, ypos, zpos, xrot, yrot;
extern float heroDist;
extern float heroPosition[3];
extern float cameraPosition[3];
extern float altura;
extern enum GameMode { FPS, RPG } gameMode;
extern ILint heightW, heightH;
extern float heightMap[TERRAINLENGTH*2][TERRAINLENGTH*2];
extern FrustumG frustum;

Camera::Camera() {
}

void Camera::cameraFPS() {
	glTranslatef(0.0f, -altura, 0.0f);
	//heroClass->drawHero();
	//heroClass->drawHeroMD2();
	glRotatef(xrot,1.0,0.0,0.0);  
	glRotatef(yrot,0.0,1.0,0.0);  
	glTranslatef(-xpos,-2.0f,-zpos); 
}

void Camera::cameraRPG() {
	glTranslatef(0.0f, -altura, -heroDist);
	glRotatef(xrot,1.0,0.0,0.0); // the hero turns with camera when it moves on the x-axis
	//heroClass->drawHero();
	heroClass->drawHeroMD2();
	glRotatef(yrot,0.0,1.0,0.0); 
	glTranslatef(-xpos,-2.0f,-zpos);
}

void Camera::updateCamerasPosition() {
  altura = heightMap[(int)xpos+TERRAINLENGTH][(int)zpos+TERRAINLENGTH];
	cameraPosition[0] = xpos;
	cameraPosition[1] = altura;
	cameraPosition[2] = zpos;

	heroPosition[0] = xpos;
  heroPosition[1] = altura;
	heroPosition[2] = zpos;
}

void Camera::updateCamerasPositionRPG() {
	cameraPosition[2] -= heroDist;
}

void multMat(float *res,float *a, float *b) {

	for (int i=0;i<4;i++) {
		for (int j = 0;j < 4;j++) {
			res[i*4+j] = 0.0;
			for (int k = 0; k < 4; k++) {
				res[i*4+j] += a[i*4+k] * b[k*4+j];
			}
		}
	}
}

void Camera::placeCamera() {
	if (gameMode == FPS) {
		cameraFPS();
		updateCamerasPosition();
	}
	else if (gameMode == RPG) {
		cameraRPG();
		updateCamerasPosition();
		updateCamerasPositionRPG();
	}

	//Prepare view frustum culling
	float m[16],p[16],res[16];
	glGetFloatv(GL_PROJECTION_MATRIX,p);
	glGetFloatv(GL_MODELVIEW_MATRIX,m);
	multMat(res,m,p);
	frustum.setFrustum(res);
}